
#include <g-bios.h>
#include <core/fs.h>
#include <flash/flash.h>
#include <image.h>


typedef struct 
{
	unsigned chunkId:20;
	unsigned serialNumber:2;
	unsigned byteCount:10;
	unsigned objectId:18;
	unsigned ecc:12;
	unsigned unusedStuff:2;
} YAFFS_TAGS;


typedef union 
{
	YAFFS_TAGS asTags;
	UINT8 asBytes[8];
} YAFFS_TAGS_UNION;


//fixme: tmp code
static struct NandOobLayout g_yaffs_oob = 
{
	.nEccCodeNum = 6,
	.piEccPos    = {8, 9, 10, 13, 14, 15},
	.mFreeRegion =
	{
		{.nOfOffset = 0, .nOfLen = 4},
		{.nOfOffset = 6, .nOfLen = 2},
		{.nOfOffset = 11, .nOfLen = 2}
	}
};


static void YaffsCalcTagsECC(YAFFS_TAGS * tags)
{
	unsigned char *b = ((YAFFS_TAGS_UNION *)tags)->asBytes;
	unsigned i, j;
	unsigned ecc = 0;
	unsigned bit = 0;

	tags->ecc = 0;

	for (i = 0; i < 8; i++)
	{
		for (j = 1; j & 0xff; j <<= 1)
		{
			bit++;
			if (b[i] & j)
			{
				ecc ^= bit;
			}
		}
	}

	tags->ecc = ecc;
}


static int YaffsCheckECCOnTags(YAFFS_TAGS * tags)
{
	unsigned ecc = tags->ecc;

	YaffsCalcTagsECC(tags);

	ecc ^= tags->ecc;

	if (ecc && ecc <= 64)
	{
		unsigned char *b = ((YAFFS_TAGS_UNION *)tags)->asBytes;

		ecc--;
		b[ecc / 8] ^= (1 << (ecc & 7));
		YaffsCalcTagsECC(tags);

		return 1;
	}
	else if (ecc)
	{
		return -1;
	}

	return 0;
}


static BOOL IsYaffsImage(const void *pImageBuf)
{
	BYTE FreeOobBuf[YAFFS_OOB_SIZE];
	struct OobFreeRegion *free;
	UINT32 nOffset = 0;
	ULONG nBytes = 0;
	int nRet;
	BYTE *pOobBuf = FreeOobBuf;


	memset(FreeOobBuf, 0, YAFFS_OOB_SIZE);

	for(free = g_yaffs_oob.mFreeRegion; free->nOfLen; free++)
	{
		nBytes  = free->nOfLen;
		nOffset = free->nOfOffset;

		memcpy(pOobBuf, pImageBuf + nOffset, nBytes);
		pOobBuf += nBytes;
	}

	nRet = YaffsCheckECCOnTags((YAFFS_TAGS *)FreeOobBuf);
	if (nRet < 0)
		return FALSE;

	return TRUE;
}

BOOL GuImageCheck(PART_TYPE nType, const BYTE *pBuff)
{
	if (!pBuff)
		return FALSE;
		
	switch (nType)
	{
	case PT_BL_GBIOS:
		if (GB_MAGIC_BH != *(UINT32 *)(pBuff + GBIOS_MAGIC_OFFSET))
			goto L1;
		return TRUE;

	case PT_OS_LINUX:		
		if (LINUX_MAGIC != *(UINT32 *)(pBuff + LINUX_MAGIC_OFFSET))
			goto L1;
		return TRUE;

	case PT_FS_JFFS2:
		if ((UINT16)JFFS2_MAGIC != *(UINT16 *)(pBuff + JFFS2_MAGIC_OFFSET))
			goto L1;
		return TRUE;

	case PT_FS_YAFFS:
		return IsYaffsImage(pBuff + YAFFS_OOB_SIZE);

	case PT_FS_YAFFS2:
		break;
		
	case PT_FS_CRAMFS:
		return TRUE; //fixme

	default:
		return TRUE; // tmp, fixme!!!
		break;
	}

L1:
	return TRUE; // fixme!
}

